﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Collections;
using Medianamik.Core.Querying;
using Medianamik.Core.Interfaces;

namespace Medianamik.Core.Caching
{
    public class CurrentRequestCacheProvider : INodeCacheProvider
    {
        protected virtual NodeBag NodeBag
        {
            get
            {
                return HttpContext.Current.Items["NodeBag"] as NodeBag
                     ?? (NodeBag)(HttpContext.Current.Items["NodeBag"] = new NodeBag());
            }
        }

        public int GetNodeCount(IQueryDefinition pQueryDef)
        {
            return new NullCacheProvider().GetNodeCount(pQueryDef);
        }

        public virtual IEnumerable<Node> GetNodes(IQueryDefinition pQueryDef)
        {
            return GetNodes(pQueryDef, false);
        }
        public virtual IEnumerable<Node> GetNodes(IQueryDefinition pQueryDef, bool withDeletedNodes)
        {
            if (HttpContext.Current == null)
            {
                foreach (var node in new NullCacheProvider().GetNodes(pQueryDef, withDeletedNodes))
                {
                    yield return node;
                }
            }
            else if (!pQueryDef.NodeTypeWheres.Any()
                     && !pQueryDef.PropertyWheres.Any()
                     && pQueryDef.NodeWheres.Any()
                     && pQueryDef.NodeWheres[0].MemberInfo.Name == "ID"
                     && (pQueryDef.NodeWheres[0].Comparison == Comparison.In
                         || pQueryDef.NodeWheres[0].Comparison == Comparison.Equal))
            {
                var value = pQueryDef.NodeWheres[0].Value;
                if (value is IEnumerable<Guid>)
                {
                    var nodes = NodeBag.Dig((IEnumerable<Guid>)value, (ids) => BuildQuery(ids, withDeletedNodes).Execute());
                    foreach (var node in nodes)
                    {
                        yield return node;
                    }
                }
                else
                {
                    if (value is Guid)
                    {
                        var node = NodeBag.Dig((Guid)value, (id) => BuildQuery(id, withDeletedNodes).Execute().FirstOrDefault());
                        if (node != null)
                        {
                            yield return node;
                        }
                    }
                }
            }
            else
            {
                var nodes = DALProviderManager.DALProvider.NodeDALProvider.GetNodes(pQueryDef, withDeletedNodes);
                List<Node> addedNodes = new List<Node>();
                List<Node> diggedNodes = new List<Node>();
                foreach (var node in nodes)
                {
                    var diggedNode = NodeBag.Dig(node);
                    diggedNodes.Add(diggedNode);
                    bool added = object.ReferenceEquals(node, diggedNode);
                    if (added)
                    {
                        addedNodes.Add(node);
                    }
                }
                foreach (var node in diggedNodes)
                {
                    yield return node;
                }
            }
        }

        public Query BuildQuery(IEnumerable<Guid> pNodeIds, bool withDeletedNodes)
        {
            return new Query(new NullCacheProvider(), default(IQueryDefinition),withDeletedNodes)
            .Where(n => n.ID, Comparison.In, pNodeIds.ToArray());
        }

        public Query BuildQuery(Guid pNodeId, bool withDeletedNodes)
        {
            return new Query(new NullCacheProvider(), default(IQueryDefinition), withDeletedNodes)
            .Where(n => n.ID, Comparison.Equal, pNodeId);
        }
    }
}
